package com.fw4j.web.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fw4j.configure.XmlParse;
import com.fw4j.web.annotation.Action;
import com.fw4j.web.annotation.COOKIE;
import com.fw4j.web.annotation.Parameter;
import com.fw4j.web.annotation.RequestMapping;
import com.fw4j.web.mapping.URLMapping;

import freemarker.template.Configuration;
/**
 * @author 穆仁超
 * Servlet调度器
 * 日期 2013-12-24 16:59
 * 这是一个简单的框架，使用注释达到零配置的目的。
 * 有时间在完善这个程序吧!
 * 我的QQ群：32894018
 * Email : minix3@126.com
 */
public class DispatcherServlet extends PagerJump {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static Logger logger = LoggerFactory.getLogger(DispatcherServlet.class);
	private static String encoding = "UTF-8";

		
	@Override
	public void init(){
		XmlParse xp = XmlParse.getInstance();
		encoding = xp.getFw4jCnfigure().getCconfigure().getEncoding();
		logger.info("编码格式"+encoding);
		ClassLoader loader = Thread.currentThread().getContextClassLoader(); 
		String filePath = xp.getFw4jCnfigure().getCconfigure().getValue(); 
		filePath = filePath.replace(".", "/"); 
		URL url = loader.getResource(filePath);
		URLMapping.createMapping(URLMapping.scanningClass(url.getPath()));
		String freemaker = xp.getFw4jCnfigure().getCconfigure().getView();
		if(freemaker != null){
			//设置FreeMaker的位置 
			cfg = new Configuration();
			cfg.setServletContextForTemplateLoading(getServletContext(), freemaker);
		}//]if
		String jsp = xp.getFw4jCnfigure().getCconfigure().getView();
		if(jsp != null){
			jspPath = "/"+jsp;
		}//]if
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StringBuilder urlPath = urlPath(request);
		urlPath.append("$");
		urlPath.append(RequestMapping.Method.GET);
		String classPath  = URLMapping.getURLMapping(urlPath.toString());
		if(classPath==null){
			response.sendError(404);
			return;
		}//]if
		commonServlet(request, response,classPath);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		StringBuilder urlPath = urlPath(request);
		urlPath.append("$");
		urlPath.append(RequestMapping.Method.POST);
		String classPath  = URLMapping.getURLMapping(urlPath.toString());
		if(classPath==null){
			response.sendError(404);
			return;
		}//]if
		commonServlet(request, response,classPath);
	}
	
	
	private StringBuilder urlPath(HttpServletRequest request) {
		StringBuilder urlPath = new StringBuilder(request.getRequestURI());
		int lastSym = urlPath.lastIndexOf("/");
		int pathLength = urlPath.length();
		if(urlPath.toString().equals("/")){
			urlPath.append("index");
		}else if(lastSym+1 == pathLength){
			urlPath.replace(lastSym, pathLength, "");
		}//]if
		return urlPath;
	}

	private void commonServlet(HttpServletRequest request,HttpServletResponse response,String classPath) {
		try {
			//System.out.println("DispatcherServlet : "+Thread.currentThread().getName());
			request.setCharacterEncoding(encoding);
			String[] cpath = classPath.split("_");
			String method = cpath[1];
			classPath = cpath[0];
			
			Object c = Class.forName(classPath).newInstance();
			if(c == null){
				response.sendError(404);
				return;
			}//]if
			Method[] ms = c.getClass().getMethods();
			Method m = null;
			for(Method md : ms){
				if(md.getName().equals(method)){
					m = md;
					break;
				}//]if
			}//]for
			Class<?>[] paramtype = m.getParameterTypes();
			List<Object> params = new ArrayList<Object>();
			OutParameter<String,Object> outparam = null;
			int ptlength = paramtype.length;
			//获得参数中的注释
			if(ptlength>0){
				Annotation[][] ps = m.getParameterAnnotations();
				int i=0;
				i = getParamterValue(request, params, ps, i);
				//获得要获得的其他参数值
				for(;i<ptlength;i++){
					if(paramtype[i] == HttpServletRequest.class){
						params.add(request);
					}else if(paramtype[i]== HttpServletResponse.class){
						params.add(response);
					}else if(paramtype[i] == PrintWriter.class){
						params.add(response.getWriter());
					}else if(paramtype[i] == Cookie[].class){
						params.add(request.getCookies());
					}else if(paramtype[i] == OutParameter.class){
						outparam = new OutMap<String,Object>();
						params.add(outparam);
					}//]if
				}//]for
			}//]if
			
			Object retVal = null;
			if(params != null && params.size()>0){
				retVal = m.invoke(c, params.toArray());
			}else{
				try{
					retVal = m.invoke(c,null);
				}catch(Exception ex){}
			}//]if
			//获得Action注解
			Annotation[] anns = m.getAnnotations();
			for(Annotation as : anns){
				if(as instanceof Action){
					Action an = (Action)as;
					System.out.println(an);
					if(an.type().length>0){
					   if(retVal instanceof Integer || retVal.getClass().equals(int.class)){
						  int index = Integer.parseInt(retVal.toString());
//						  System.out.println(index);
//						  System.out.println(an.result()[index]);
						  if(an.type()[index] == Action.Type.REQUEST){
							  jumpPage(request, response,an.result()[index],outparam);
						  }else if(an.type()[index] == Action.Type.REDIRECT){
							  System.out.println("redirect:"+an.result()[index]);
							  jumpPage(request, response,"redirect:"+an.result()[index],outparam);
						  }else if(an.type()[index] == Action.Type.TOJSON){
							  jumpPage(request, response,retVal,outparam);
						  }//]if
					   }//]if
					}//]if
				}//]if
			}//]for
			jumpPage(request, response,retVal,outparam);
		} catch (Exception ex){
			ex.printStackTrace();
		}
	}

	private int getParamterValue(HttpServletRequest request,
			List<Object> params, Annotation[][] ps, int i) {
		for(Annotation[] a : ps){
			for(Annotation a2 : a){
				if(a2 instanceof Parameter){
					Parameter p = (Parameter)a2;
					if(p.value() != null){
						String[] pams = p.value();
						for(String name : pams){
							i++;
							params.add(request.getParameter(name));
						}//]for
					}//]if
				}else if(a2 instanceof com.fw4j.web.annotation.COOKIE){
					COOKIE acookie = (COOKIE)a2;
					if(acookie.value().length>0){
						Cookie[] cookies = request.getCookies();
						if(cookies!=null){
							Map<String,Object> cm = new HashMap<String,Object>();
							for(Cookie cookie : cookies){
								cm.put(cookie.getName(), cookie);
							}//]for
							String[] cnames = acookie.value();
							for(String name : cnames){
								i++;
								if(cm.containsKey(name)){
									params.add(cm.get(name));
								}else{
									params.add(null);
								}//]if
							}//]for
						}else{
							params.add(null);
						}//]if
					}//]if
				}//]if
			}//]for
		}//]for
		return i;
	}
}